<?php

namespace sws\route;

use sws\Container;


class Route
{

    /**
     * 路由解析树
     * @var array
     */
    private $routeTree = ['static' => [], 'dynamic' => []];

    /**
     * 路由对象列表
     * @var array
     */
    private $routeRuleList = [];

    /**
     * 当前路由分组
     * @var RouteGroup
     */
    private $routeGroup;

    /**
     * 初始化一个默认的路由分组
     */
    public function __construct()
    {
        $this->routeGroup = new RouteGroup();
    }

    /**
     * 添加分组
     * @param string   $groupName
     * @param callable $callback
     * @return RouteGroup
     */
    protected function group(string $groupName, callable $callback): RouteGroup
    {
        $previousRouteGroup = $this->routeGroup;
        $routeGroup = new RouteGroup($previousRouteGroup, $groupName);
        $this->routeGroup = $routeGroup;
        $callback();
        $this->routeGroup = $previousRouteGroup;
        return $routeGroup;
    }

    /**
     * GET路由
     * @param string $route
     * @param        $handler
     * @return RouteRule
     */
    protected function get(string $route, $handler): RouteRule
    {
        return $this->addRoute('GET', $route, $handler);
    }

    /**
     * 添加路由
     * @param        $method
     * @param string $route
     * @param        $handler
     * @return RouteRule
     */
    protected function addRoute($method, string $route, $handler): RouteRule
    {
        $routeRule = $this->routeGroup->addRoute($method, $route, $handler);
        $this->routeRuleList[] = $routeRule;
        return $routeRule;
    }

    /**
     * POST路由
     * @param string $route
     * @param        $handler
     * @return RouteRule
     */
    protected function post(string $route, $handler): RouteRule
    {
        return $this->addRoute('POST', $route, $handler);
    }

    /**
     * DELETE路由
     * @param string $route
     * @param        $handler
     * @return RouteRule
     */
    protected function delete(string $route, $handler): RouteRule
    {
        return $this->addRoute('DELETE', $route, $handler);
    }

    /**
     * HEAD路由
     * @param string $route
     * @param        $handler
     * @return RouteRule
     */
    protected function head(string $route, $handler): RouteRule
    {
        return $this->addRoute('HEAD', $route, $handler);
    }

    /**
     * PATCH路由
     * @param string $route
     * @param        $handler
     * @return RouteRule
     */
    protected function patch(string $route, $handler): RouteRule
    {
        return $this->addRoute('PATCH', $route, $handler);
    }

    /**
     * PUT路由
     * @param string $route
     * @param        $handler
     * @return RouteRule
     */
    protected function put(string $route, $handler): RouteRule
    {
        return $this->addRoute('PUT', $route, $handler);
    }

    /**
     * OPTION路由
     * @param string $route
     * @param        $handler
     * @return RouteRule
     */
    protected function option(string $route, $handler): RouteRule
    {
        return $this->addRoute('OPTION', $route, $handler);
    }

    /**
     * ANY路由
     * @param string $route
     * @param        $handler
     * @return RouteRule
     */
    protected function any(string $route, $handler): RouteRule
    {
        return $this->addRoute('*', $route, $handler);
    }

    /**
     * 解析路由到列表
     */
    public function parserRoute()
    {
        /**@var RouteRule $routeRule * */
        foreach ($this->routeRuleList as $routeRule) {
            $tree = $routeRule->getRouteTree();
            foreach ($tree as $type => $value1) {
                foreach ($value1 as $method => $value2) {
                    foreach ($value2 as $url => $value3) {
                        if (isset($this->routeTree[$type][$method][$url])) {
                            continue;
                        } else {
                            $this->routeTree[$type][$method][$url] = $value3;
                        }
                    }
                }
            }
        }
        //删除路由对象，释放内存
        unset($this->routeRuleList);
    }

    /**
     * 获取路由树
     * @return array|array[]
     */
    public function getRouteTree(): array
    {
        return $this->routeTree;
    }

    /**
     * 匹配路由
     * @param string $method
     * @param string $uri
     * @return array|null
     */
    public function match(string $method, string $uri): ?array
    {
        if (isset($this->routeTree['static'][$method][$uri])) {
            return [false, $this->routeTree['static'][$method][$uri]];
        }

        $tree = $this->routeTree['dynamic'][$method] ?? [];
        foreach ($tree as $key => $value) {
            if (preg_match('|^' . $key . '$|', $uri, $matches)) {
                $value['matches'] = $matches;
                return [true, $value];
            }
        }
        return null;
    }


    /**
     * @param $method
     * @param $params
     * @return mixed
     */
    public static function __callStatic($method, $params)
    {
        return call_user_func_array([Container::getInstance()->make(Route::class), $method], $params);
    }


}




